"""
视频裁剪模块：处理视频裁剪相关的功能
包括单个视频裁剪、进度查询、文件管理等
"""

import os
import time
import asyncio
import re
import uuid
import json
import sqlite3
from pathlib import Path
from fastapi import HTTPException
from fastapi.responses import JSONResponse, FileResponse
from bbdown.core.logger import Logger

from .constants import UPLOAD_DIR, CUT_DIR, CUT_TASKS, DB_PATH
from .db import insert_result, update_task_filename, update_result_filename, get_task, get_task_files, update_task_status

logger = Logger()

def restore_cut_tasks():
    """
    从数据库恢复裁剪任务信息
    """
    try:
        # 获取所有裁剪任务
        conn = sqlite3.connect(DB_PATH)
        c = conn.cursor()
        c.execute('SELECT id, params, status, result FROM task WHERE type = "cut"')
        tasks = c.fetchall()
        conn.close()
        
        for task_id, params_str, status, result_str in tasks:
            try:
                params = json.loads(params_str)
                result = json.loads(result_str) if result_str else {}
                
                # 获取任务相关的文件
                files = get_task_files(task_id)
                if not files:
                    continue
                    
                # 获取输出文件路径
                output_path = files[0]['file_path']
                if not os.path.exists(output_path):
                    continue
                
                # 恢复任务信息
                CUT_TASKS[task_id] = {
                    "status": status,
                    "progress": 100 if status == "finished" else 0,
                    "current_step": "已完成" if status == "finished" else "处理中",
                    "output_path": output_path,
                    "custom_filename": os.path.basename(output_path),
                    "created_at": time.time(),
                    "completed_at": time.time() if status == "finished" else None
                }
                
                logger.info(f"恢复裁剪任务: {task_id}")
            except Exception as e:
                logger.error(f"恢复任务失败 {task_id}: {str(e)}")
    except Exception as e:
        logger.error(f"恢复裁剪任务失败: {str(e)}")

# 启动时恢复任务
# restore_cut_tasks()

async def cut_video(
    video: bytes,
    filename: str,
    start_time: str,
    end_time: str,
    user_id: str = None
) -> dict:
    """
    处理视频裁剪请求
    
    参数：
        video (bytes): 视频文件内容
        filename (str): 视频文件名
        start_time (str): 开始时间
        end_time (str): 结束时间
        user_id (str): 用户ID
        
    返回：
        dict: 包含任务ID和状态的字典
    """
    task_id = str(uuid.uuid4())
    try:
        # 保存上传的视频
        input_path = UPLOAD_DIR / f"{task_id}_{filename}"
        with open(input_path, "wb") as f:
            f.write(video)
            
        # 设置输出路径
        output_path = CUT_DIR / f"{task_id}_cut_{filename}"
        
        # 初始化任务状态
        CUT_TASKS[task_id] = {
            "status": "running",
            "progress": 0,
            "current_step": "正在裁剪视频...",
            "input_path": str(input_path),
            "output_path": str(output_path),
            "created_at": time.time()
        }
        
        # 启动裁剪任务
        asyncio.create_task(
            cut_task(
                task_id,
                str(input_path),
                str(output_path),
                start_time,
                end_time
            )
        )
        
        return {"task_id": task_id}
    except Exception as e:
        logger.error(f"处理裁剪请求失败: {str(e)}")
        return {"error": str(e), "task_id": task_id}

async def cut_task(task_id: str, input_path: str, output_path: str, start_time: str, end_time: str):
    """
    后台裁剪任务
    
    参数：
        task_id (str): 任务ID
        input_path (str): 输入文件路径
        output_path (str): 输出文件路径
        start_time (str): 开始时间
        end_time (str): 结束时间
    """
    try:
        # 更新任务状态为运行中
        update_task_status(task_id, "running")
        
        # 使用ffprobe获取视频时长
        duration_cmd = [
            'ffprobe',
            '-v', 'error',
            '-show_entries', 'format=duration',
            '-of', 'default=noprint_wrappers=1:nokey=1',
            input_path
        ]
        
        process = await asyncio.create_subprocess_exec(
            *duration_cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await process.communicate()
        video_duration = float(stdout.decode().strip())
        
        # 计算裁剪时长
        start_seconds = sum(int(x) * (60 ** i) for i, x in enumerate(reversed(start_time.split(':'))))
        end_seconds = sum(int(x) * (60 ** i) for i, x in enumerate(reversed(end_time.split(':'))))
        cut_duration = end_seconds - start_seconds
        
        # 如果裁剪时长小于视频总时长的10%，使用快速模式
        if cut_duration < video_duration * 0.1:
            # 快速模式：使用 -c copy 和关键帧定位
            cmd = [
                'ffmpeg',
                '-ss', start_time,  # 先定位到开始时间
                '-i', input_path,   # 然后读取输入
                '-t', str(cut_duration),  # 设置裁剪时长
                '-c', 'copy',       # 使用快速复制模式
                '-avoid_negative_ts', '1',  # 避免负时间戳
                output_path
            ]
        else:
            # 标准模式：重新编码以确保精确性
            cmd = [
                'ffmpeg',
                '-i', input_path,
                '-ss', start_time,
                '-to', end_time,
                '-c:v', 'libx264',
                '-preset', 'medium',
                '-crf', '23',
                '-c:a', 'aac',
                '-b:a', '128k',
                output_path
            ]
        
        process = await asyncio.create_subprocess_exec(
            *cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        
        # 等待处理完成
        stdout, stderr = await process.communicate()
        
        if process.returncode == 0:
            # 更新内存中的任务状态
            CUT_TASKS[task_id].update({
                "status": "finished",
                "progress": 100,
                "current_step": "裁剪完成"
            })
            # 更新数据库中的任务状态
            update_task_status(task_id, "finished", {
                "output_path": str(output_path),
                "file_name": os.path.basename(output_path)
            })
            # 插入结果表
            if os.path.exists(output_path):
                insert_result(
                    task_id,
                    os.path.basename(output_path),
                    str(output_path),
                    os.path.getsize(output_path),
                    "video/mp4"
                )
        else:
            error_msg = f"裁剪失败: {stderr.decode()}"
            # 更新内存中的任务状态
            CUT_TASKS[task_id].update({
                "status": "error",
                "error": error_msg
            })
            # 更新数据库中的任务状态
            update_task_status(task_id, "error", {"error": error_msg})
            
    except Exception as e:
        error_msg = str(e)
        # 更新内存中的任务状态
        CUT_TASKS[task_id].update({
            "status": "error",
            "error": error_msg
        })
        # 更新数据库中的任务状态
        update_task_status(task_id, "error", {"error": error_msg})
    finally:
        # 清理输入文件
        try:
            if os.path.exists(input_path):
                os.remove(input_path)
        except:
            pass
        
        # 更新任务完成时间
        if task_id in CUT_TASKS:
            CUT_TASKS[task_id]["completed_at"] = time.time()

def get_cut_progress(task_id: str) -> dict:
    """
    获取裁剪进度
    
    参数：
        task_id (str): 任务ID
        
    返回：
        dict: 任务状态信息
    """
    if task_id not in CUT_TASKS:
        raise HTTPException(status_code=404, detail="任务不存在")
    return CUT_TASKS[task_id]

def get_cut_file(task_id: str) -> FileResponse:
    """
    获取裁剪后的视频文件
    
    参数：
        task_id (str): 任务ID
        
    返回：
        FileResponse: 文件响应
    """
    if task_id not in CUT_TASKS:
        raise HTTPException(status_code=404, detail="任务不存在")
    
    task = CUT_TASKS[task_id]
    if task["status"] != "finished":
        raise HTTPException(status_code=400, detail="视频尚未处理完成")
    
    output_path = task["output_path"]
    if not os.path.exists(output_path):
        raise HTTPException(status_code=404, detail="文件不存在")
    
    # 获取文件名（不包含路径）
    filename = os.path.basename(output_path)
    # 如果任务中有自定义文件名，使用自定义文件名
    if "custom_filename" in task:
        filename = task["custom_filename"]
    
    # 更新最后访问时间
    task["last_accessed"] = time.time()
    
    return FileResponse(
        output_path,
        filename=filename,
        media_type="video/mp4"
    )

def rename_cut_file(task_id: str, new_name: str) -> dict:
    """
    重命名裁剪后的视频文件
    
    参数：
        task_id (str): 任务ID
        new_name (str): 新文件名
        
    返回：
        dict: 重命名结果
    """
    logger.info(f"开始重命名文件，任务ID: {task_id}, 新文件名: {new_name}")
    logger.info(f"当前CUT_TASKS: {CUT_TASKS}")
    
    if task_id not in CUT_TASKS:
        logger.error(f"任务不存在: {task_id}")
        raise HTTPException(status_code=404, detail="任务不存在")
        
    task = CUT_TASKS[task_id]
    if task["status"] != "finished":
        logger.error(f"视频尚未处理完成: {task_id}")
        raise HTTPException(status_code=400, detail="视频尚未处理完成")
        
    output_path = task["output_path"]
    if not os.path.exists(output_path):
        logger.error(f"文件不存在: {output_path}")
        raise HTTPException(status_code=404, detail="文件不存在")
        
    # 确保新文件名有.mp4后缀
    if not new_name.endswith('.mp4'):
        new_name += '.mp4'
        
    # 记录旧文件名
    old_name = task.get("custom_filename", os.path.basename(output_path))
    logger.info(f"旧文件名: {old_name}")
    
    # 更新任务中的自定义文件名
    task["custom_filename"] = new_name
    
    # 更新数据库中的文件名
    update_task_filename(task_id, new_name)
    update_result_filename(task_id, old_name, new_name)
    
    logger.info(f"重命名成功: {old_name} -> {new_name}")
    return {
        "status": "success",
        "new_filename": new_name,
        "old_filename": old_name
    }

async def get_cut_preview(task_id: str) -> dict:
    """
    获取视频预览信息
    
    参数：
        task_id (str): 任务ID
        
    返回：
        dict: 视频预览信息
    """
    if task_id not in CUT_TASKS:
        raise HTTPException(status_code=404, detail="任务不存在")
    
    task = CUT_TASKS[task_id]
    if task["status"] != "finished":
        raise HTTPException(status_code=400, detail="视频尚未处理完成")
    
    output_path = task["output_path"]
    if not os.path.exists(output_path):
        raise HTTPException(status_code=404, detail="文件不存在")
    
    # 获取文件信息
    file_size = os.path.getsize(output_path)
    duration = 0
    
    # 使用ffprobe获取视频时长
    try:
        cmd = [
            'ffprobe',
            '-v', 'error',
            '-show_entries', 'format=duration',
            '-of', 'default=noprint_wrappers=1:nokey=1',
            output_path
        ]
        process = await asyncio.create_subprocess_exec(
            *cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await process.communicate()
        if process.returncode == 0:
            duration = float(stdout.decode().strip())
    except:
        pass
    
    return {
        "filename": task.get("custom_filename", os.path.basename(output_path)),
        "size": file_size,
        "duration": duration,
        "url": f"/api/cut/file/{task_id}"
    } 